import numpy as np
import random


def dict_sort():
    """
    实现无序dict的有序排列
    input：dict；
    output：list;
    """
    d = {}
    d['foo'] = 1
    d['bar'] = 4
    d['spam'] = 4
    d['grok'] = 3
    if len(d) < 1:
        print('dict is empty set')
        return 0
    # 调用python API
    d_x = sorted(d.items(), key=lambda d: d[1])
    print(d_x)
    # 自己实现
    d_x = []
    value = []
    for (k, v) in d.items():
        value.append((v,k))
    value.sort()
    for i in range(0, len(value)):
        d_x.append((value[i][1], value[i][0]))
    print(d_x)


# 补零
def zero_pad(X_in, pad):
    X_pad = np.pad(X_in, ((0, 0), (pad, pad), (pad, pad), (0, 0)), mode='constant', constant_values=(0, 0))
    # 样本数维度，不填充# n_H维度，上下各填充pad个像素# n_W维度，上下各填充pad个像素# n_C维度，不填充
    return X_pad


# 单步卷积
def single_conv_step( a_slice, filter_w, filter_b):
    s = a_slice * filter_w
    z = np.sum(s)
    z = z + float(filter_b)
    return z


def conv_forward(input_prev, filter_w, filter_b, filter_size, stride, pad):
    #
    (pre_C, pre_H, pre_W) = input_prev.shape
    # filter_b -- 偏置参数 (1, 1, 1, n_C)
    # 权重参数filter_w，这一层的卷积核参数 (f, f, n_C_prev, n_C)，n_C个大小为（f,f,n_C_prev）的卷积核
    (f, f, n_C_prev, n_C) = filter_w.shape
    # 计算输出结果的维度
    res_H = int((pre_H - filter_size) / stride) + 1
    res_W = int((pre_W - filter_size) / stride) + 1
    result = np.zeros((res_H, res_W))
    input_prev_pad = zero_pad(input_prev, pad)
    for h in range(res_H):  # 在输出结果的垂直方向上循环
        for w in range(res_W):  # 在输出结果的水平方向上循环
            # 确定分片边界
            vert_start = h * stride
            vert_end = vert_start + f
            horiz_start = w * stride
            horiz_end = horiz_start + f

            for c in range(n_C):  # 遍历输出的通道
                # 在输入数据上获取当前切片，结果是3D
                a_slice_prev = a_prev_pad[vert_start:vert_end, horiz_start:horiz_end, :]
                # 获取当前的卷积核参数
                weights = filter_w[:, :, c]
                biases = filter_b[:, :, c]
                # 输出结果当前位置的计算值，使用单步卷积函数
                Z[i, h, w, c] = conv_single_step(a_slice_prev, weights, biases)
    assert (Z.shape == (res_H, res_W, n_C))
    # 将本层数据缓存，方便反向传播时使用
    cache = (A_prev, W, b, hparameters)
    return result


def cnn_numpy(input_data):
    """
    由python实现cnn
    input：3*32*32大小；
    output：一个score;
    """
    # 初始化参数
    filter_w = np.random.randn(3, 3, 4, 8)
    filter_b = np.random.randn(1, 1, 1, 8)
    filter_size = 2
    stride = 1
    pooling_size = 6
    pad = 1

    # 卷积层 forward + backward
    # cnn forward
    conv_result = conv_forward(input_data, filter_w, filter_b, filter_size, stride, pad)
    # cnn backward
    cnn_result = conv_result

    # 池化层

    # 全连接层

    # loss

    # softmax层

    print('done')
    return cnn_result


if __name__ == '__main__':
    # dict_sort()
    input_data = np.random.rand(32, 32, 3)   # (H, W, C)
    # execute cnn
    segment_args = cnn_numpy(input_data)